///////////////////////////////////////////////////////////////////////////////
//
// DBT86 Project : x86 Platform : x86.h
// Copyright (C) 2004 by Ben Hertzberg and Stanford University
// All Rights Reserved
//
// This code may not be used for any purpose without the express written
// consent of the author.  See the LICENSE.txt file for details.
//
//
// DESCRIPTION
//
// This header contains x86-specific definitions used in decoding and
// interpretation.
//
///////////////////////////////////////////////////////////////////////////////


#ifndef __X86_H__
#define __X86_H__

#include "common.h"

typedef UINT8  BYTE;
typedef UINT16 WORD;
typedef UINT32 DWORD;
typedef UINT64 QWORD;

#define EAX 0
#define ECX 1
#define EDX 2
#define EBX 3
#define ESP 4
#define EBP 5
#define ESI 6
#define EDI 7

#define AX 0
#define CX 1
#define DX 2
#define BX 3
#define SP 4
#define BP 5
#define SI 6
#define DI 7

#define AL 0
#define CL 1
#define DL 2
#define BL 3
#define AH 4
#define CH 5
#define DH 6
#define BH 7

#define ES 0
#define CS 1
#define SS 2
#define DS 3
#define FS 4
#define GS 5

#define EFLAGS_BIT_ID       0x00200000
#define EFLAGS_BIT_VIP      0x00100000
#define EFLAGS_BIT_VIF      0x00080000
#define EFLAGS_BIT_AC       0x00040000
#define EFLAGS_BIT_VM       0x00020000
#define EFLAGS_BIT_RF       0x00010000
// this bit hard zero       0x00008000
#define EFLAGS_BIT_NT       0x00004000
#define EFLAGS_EXTR_IOPL(x) (((x) >> 12) & 0x3)
#define EFLAGS_BIT_O        0x00000800
#define EFLAGS_BIT_D        0x00000400
#define EFLAGS_BIT_I        0x00000200
#define EFLAGS_BIT_T        0x00000100
#define EFLAGS_BIT_S        0x00000080
#define EFLAGS_BIT_Z        0x00000040
// this bit hard zero       0x00000020
#define EFLAGS_BIT_A        0x00000010
// this bit hard zero       0x00000008
#define EFLAGS_BIT_P        0x00000004
// this bit hard one        0x00000002
#define EFLAGS_BIT_C        0x00000001

#define EFLAGS_BITS_USER    (EFLAGS_BIT_C | EFLAGS_BIT_P | EFLAGS_BIT_A | EFLAGS_BIT_Z | EFLAGS_BIT_S | EFLAGS_BIT_D | EFLAGS_BIT_O | EFLAGS_BIT_ID)

#define FP_STATUS_C3          0x4000
#define FP_STATUS_C2          0x0400
#define FP_STATUS_C1          0x0200
#define FP_STATUS_C0          0x0100
#define FP_STATUS_EXCEPT_BITS 0x80FF

// hack for obtaining desired pointer-to-member behavior
// TODO: consider how to achieve this on other platforms
#ifdef LESS86
#pragma pointers_to_members( full_generality, single_inheritance )
#endif
class x86CodeGen;
typedef enum _GenSize{ SZ_X=0, SZ_B=1, SZ_H=2, SZ_W=3, SZ_D=4, SZ_BH=5, SZ_BW=6, SZ_BD=7, SZ_HW=8, SZ_HD=9, SZ_WD=10, SZ_T=11} GenSize;
typedef void (*PINSTRFUNC)();
typedef void (x86CodeGen::*PGENFUNC)();

typedef struct {
  PINSTRFUNC func[2];
#if CFG_CODEGEN
  PGENFUNC genfunc;
#endif
  UINT bits;
#if CFG_CODEGEN
  UINT genClass;
  GenSize genSize[2];
  UINT genSubOp[2];
#endif
} x86DecodeEntry;

typedef struct {
  BYTE base;
  BYTE index;
  BYTE seg;
  BYTE disp;
} ModRMEntry;

typedef struct {
  BYTE base;
  BYTE index;
  BYTE seg;
  BYTE scale;
} SIBEntry;

typedef struct {
  IVAL base;
  IVAL limit;
} SegmentInfoEntry;

extern x86DecodeEntry x86Table1[256];
extern x86DecodeEntry x86Table2[256];
extern x86DecodeEntry* x86TableGroup[];
extern x86DecodeEntry* x86TableFP[];

extern ModRMEntry RM16Table[24];
extern ModRMEntry RM32Table[24];
extern SIBEntry SIBTable[256];

#define SEG_NONE 6
// TODO: X64
#define X86_NUM_GPR 8
#define RZERO X86_NUM_GPR
#define X86_NUM_FPR 8
#define X86_NUM_SEG 6

#define ACCESS_READ      1
#define ACCESS_WRITE     2
#define ACCESS_EXECUTE   4

// TODO: consider separate memory unit or something
UINT8 LoadSegB(IVAL va, UINT seg, bool uncached = false);
UINT16 LoadSegH(IVAL va, UINT seg, bool uncached = false);
UINT32 LoadSegW(IVAL va, UINT seg, bool uncached = false);
UINT64 LoadSegD(IVAL va, UINT seg, bool uncached = false);
void StoreSegB(IVAL val, IVAL va, UINT seg, bool uncached = false);
void StoreSegH(IVAL val, IVAL va, UINT seg, bool uncached = false);
void StoreSegW(IVAL val, IVAL va, UINT seg, bool uncached = false);
void StoreSegD(IVAL val, IVAL va, UINT seg, bool uncached = false);

void SetSegSelector(UINT id, UINT16 val);
UINT16 GetSegSelector(UINT id);

// TODO: fix this hack once we have system-level simulation
// note that we need to get this from the descriptor cache
#define GetSegAttr(segID,attrID) 1
#define LOAD_VIRTUAL_BYTE(addr,seg,access) (LoadSegB(addr,seg))
#define LOAD_VIRTUAL_WORD(addr,seg,access) (LoadSegH(addr,seg))
#define LOAD_VIRTUAL_DWORD(addr,seg,access) (LoadSegW(addr,seg))
#define LOAD_VIRTUAL_UNALIGNED_WORD(addr,seg,access) (LoadSegH(addr,seg))
#define LOAD_VIRTUAL_UNALIGNED_DWORD(addr,seg,access) (LoadSegW(addr,seg))
#define LOAD_VIRTUAL_UNALIGNED_QWORD(addr,seg,access) (LoadSegD(addr,seg))

#define STORE_VIRTUAL_BYTE(val,addr,seg,access) StoreSegB(val,addr,seg)
#define STORE_VIRTUAL_WORD(val,addr,seg,access) StoreSegH(val,addr,seg)
#define STORE_VIRTUAL_DWORD(val,addr,seg,access) StoreSegW(val,addr,seg)
#define STORE_VIRTUAL_UNALIGNED_WORD(val,addr,seg,access) StoreSegH(val,addr,seg)
#define STORE_VIRTUAL_UNALIGNED_DWORD(val,addr,seg,access) StoreSegW(val,addr,seg)
#define STORE_VIRTUAL_UNALIGNED_QWORD(val,addr,seg,access) StoreSegD(val,addr,seg)

#define LOAD_VIRTUAL_BYTE_UNCACHED(addr,seg,access) (LoadSegB(addr,seg,true))
#define LOAD_VIRTUAL_WORD_UNCACHED(addr,seg,access) (LoadSegH(addr,seg,true))
#define LOAD_VIRTUAL_DWORD_UNCACHED(addr,seg,access) (LoadSegW(addr,seg,true))
#define LOAD_VIRTUAL_UNALIGNED_WORD_UNCACHED(addr,seg,access) (LoadSegH(addr,seg,true))
#define LOAD_VIRTUAL_UNALIGNED_DWORD_UNCACHED(addr,seg,access) (LoadSegW(addr,seg,true))
#define LOAD_VIRTUAL_UNALIGNED_QWORD_UNCACHED(addr,seg,access) (LoadSegD(addr,seg,true))

#define STORE_VIRTUAL_BYTE_UNCACHED(val,addr,seg,access) StoreSegB(val,addr,seg,true)
#define STORE_VIRTUAL_WORD_UNCACHED(val,addr,seg,access) StoreSegH(val,addr,seg,true)
#define STORE_VIRTUAL_DWORD_UNCACHED(val,addr,seg,access) StoreSegW(val,addr,seg,true)
#define STORE_VIRTUAL_UNALIGNED_WORD_UNCACHED(val,addr,seg,access) StoreSegH(val,addr,seg,true)
#define STORE_VIRTUAL_UNALIGNED_DWORD_UNCACHED(val,addr,seg,access) StoreSegW(val,addr,seg,true)
#define STORE_VIRTUAL_UNALIGNED_QWORD_UNCACHED(val,addr,seg,access) StoreSegD(val,addr,seg,true)

//
// These definitions are used to process the "bits" field in the
// decode tables.
//

#define X86_BITS_INITIAL          0x00010000
#define X86_BITS_MODRM            0x00020000
#define X86_BITS_LOCKABLE         0x00040000
#define X86_BITS_ALLOWREP         0x00080000
#define X86_BITS_GROUP            0x00100000
#define X86_BITS_FP               0x00200000
#define X86_BITS_EXTGROUP         0x00400000

#define X86_BITS_INITIAL_MASK     0x0000000F
// lower 4-bits meanings when X86_BITS_INITIAL is set:
#define X86_BITS_TABLE2           0x00000000
#define X86_BITS_TABLE_FP         0x00000001
#define X86_BITS_PREFIX_SEGCS     0x00000002
#define X86_BITS_PREFIX_SEGDS     0x00000003
#define X86_BITS_PREFIX_SEGES     0x00000004
#define X86_BITS_PREFIX_SEGFS     0x00000005
#define X86_BITS_PREFIX_SEGGS     0x00000006
#define X86_BITS_PREFIX_SEGSS     0x00000007
#define X86_BITS_PREFIX_LOCK      0x00000008
#define X86_BITS_PREFIX_REP       0x00000009
#define X86_BITS_PREFIX_REPNE     0x0000000A
#define X86_BITS_PREFIX_OPSIZE    0x0000000B
#define X86_BITS_PREFIX_ADDRSIZE  0x0000000C

#define X86_BITS_GROUP_MASK       0x0000001F
// lower 5-bits meaning when X86_BITS_GROUP is set:
#define X86_BITS_GROUP1A          0x00000000
#define X86_BITS_GROUP1B          0x00000001
#define X86_BITS_GROUP1C          0x00000002
#define X86_BITS_GROUP2A          0x00000003
#define X86_BITS_GROUP2B          0x00000004
#define X86_BITS_GROUP2C          0x00000005
#define X86_BITS_GROUP2D          0x00000006
#define X86_BITS_GROUP2E          0x00000007
#define X86_BITS_GROUP2F          0x00000008
#define X86_BITS_GROUP3A          0x00000009
#define X86_BITS_GROUP3B          0x0000000A
#define X86_BITS_GROUP4           0x0000000B
#define X86_BITS_GROUP5           0x0000000C
#define X86_BITS_GROUP6           0x0000000D
#define X86_BITS_GROUP7           0x0000000E
#define X86_BITS_GROUP8           0x0000000F
#define X86_BITS_GROUP9           0x00000010
#define X86_BITS_GROUP10          0x00000011
#define X86_BITS_GROUP11          0x00000012
#define X86_BITS_GROUP12          0x00000013
#define X86_BITS_GROUP13          0x00000014
#define X86_BITS_GROUP14          0x00000015
#define X86_BITS_GROUP15          0x00000016
#define X86_BITS_GROUP16          0x00000017

#define X86_BITS_IMM0_MASK        0x00000F00
#define X86_BITS_IMM8             0x00000100
#define X86_BITS_IMM16            0x00000200
#define X86_BITS_IMMV             0x00000300
#define X86_BITS_OFSV             0x00000400
#define X86_BITS_REL8             0x00000500
#define X86_BITS_RELV             0x00000600
#define X86_BITS_IMM1_MASK        0x0000F000
#define X86_BITS_IMM8_2           0x00001000
#define X86_BITS_IMMSEG           0x00002000

//
// These encodings track prefixes in the "prefixes" variable
// The high-order bits are used for prefix identification
// The low-order bits are used for table 2 mmx/sse/sse2 decode
//
#define X86_DEC_PREFIX_SEG              0x00000010
#define X86_DEC_PREFIX_LOCK             0x00000020
#define X86_DEC_PREFIX_REP              0x00000040
#define X86_DEC_PREFIX_REPNE            0x00000080
#define X86_DEC_PREFIX_OPSIZE           0x00000100
#define X86_DEC_PREFIX_ADDRSIZE         0x00000200
#define X86_DEC_PREFIX_HINT_TAKEN       0x00000400
#define X86_DEC_PREFIX_HINT_NOT_TAKEN   0x00000800
#define X86_DEC_PREFIX_SSEBIT0          0x00000001
#define X86_DEC_PREFIX_SSEBIT1          0x00000002

#endif
